#pragma once

#include <atlstr.h>
#include "GameTag.h"
class CScene;
class CCamera;

class CHeightMap;
class CTerrain;
class CPlayer;
class CCamera;


class CMesh
{
private:
	int							m_nReferences;
protected:
    LPD3DXMESH					m_pd3dxMesh; 
	DWORD						m_nAttributes;
    ATTRIBUTEITEMSTRUCT			*m_pAttributeItemIDs;   
public:
	CMesh();
    virtual ~CMesh();

	void AddRef();
	void Release();
	
	BOUNDINGCUBE				m_bcBoundingCube;
		
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED) { };
	bool LoadFromXFile(LPCTSTR lpstrFileName, DWORD dwOptions, LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
	BOOL CheckRayIntersection(LPDIRECT3DDEVICE9 pD3DDevice, D3DXMATRIX *pmtxWorld, D3DXMATRIX *pmtxView, D3DXVECTOR3 *pvPickPosition, float *pfNearHitDistance);
	BOOL CheckRayIntersection(D3DXMATRIX *pmtxWorld, D3DXVECTOR3 Pos, D3DXVECTOR3 Direction, float fRayLength, float *pfNearHitDistance);
};

class CCubeMesh : public CMesh
{
public:
	CCubeMesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
};

class CBoomMesh : public CMesh
{
public:
	CBoomMesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
};

class CSpaceShipMesh : public CMesh
{
public:
	CSpaceShipMesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
};

class CAsteroidMesh : public CMesh
{
public:
	CAsteroidMesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
};

class CCruiser01Mesh : public CMesh
{
public:
	CCruiser01Mesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
};

class CCruiser02Mesh : public CMesh
{
public:
	CCruiser02Mesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);
};

class CSkyBoxMesh : public CMesh
{
public:
	CSkyBoxMesh();
	~CSkyBoxMesh();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
};

class CGameObject
{
public:
	CGameObject(CMesh *pMesh);
	CGameObject();
	~CGameObject(void);
	void SetMesh(CMesh *pMesh);

	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CCamera *pCamera);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CCamera *pCamera, CScene *pScene);

	void MoveForward(float fDistance=0.5f);
	void MoveUpDown(float fDistance=0.5f);
	void MoveStrafe(float fDistance=0.5f);

    float           			m_fPitch;             
    float           			m_fRoll;              
    float           			m_fYaw;               

	void Rotate(float x, float y, float z);

    D3DXMATRIX					m_mtxWorld;             
    CMesh						*m_pMesh;                
};

class CSkyBox : public CGameObject
{
public:
	CSkyBox();
	~CSkyBox();
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);
	virtual void Render(LPDIRECT3DDEVICE9 pD3DDevice, CCamera *pCamera, CScene *pScene);
};




// about terrain

class CHeightMap
{
    BYTE						*m_pHeightMapImage;       
    int							m_nWidth;  
    int							m_nHeight; 
    D3DXVECTOR3					m_vScale;         
public:
	CHeightMap(void);
	~CHeightMap(void);

    bool LoadHeightMap(LPCTSTR pFileName, int nWidth, int nHeight);
    float GetHeight(float x, float z, bool bReverseQuad = false);
    D3DXVECTOR3 GetHeightMapNormal(int x, int z);
	D3DXVECTOR3 GetHeightMapNormal(float fx, float fz);
	BYTE *GetHeightMapImage() { return(m_pHeightMapImage); }
	D3DXVECTOR3 GetScale() { return(m_vScale); }
	int GetHeightMapWidth() { return(m_nWidth); }
	int GetHeightMapHeight() { return(m_nHeight); }
};



class CGridMesh : public CMesh
{
protected:
	int							m_xStart;
	int							m_zStart;
    unsigned short				m_nWidth;                  
    unsigned short				m_nHeight;                  
    unsigned short				m_cxQuads;      
    unsigned short				m_czQuads;     
public:
	CGridMesh();
	CGridMesh(int xStart, int zStart, int nWidth, int nHeight);
	~CGridMesh();
	//virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, DWORD dwUsage=0, D3DPOOL dwMemoryPool=D3DPOOL_MANAGED) { }
	virtual void Build(LPDIRECT3DDEVICE9 pD3DDevice, CHeightMap *pHeightMap, DWORD dwMeshCreateOptions=D3DXMESH_MANAGED);	
	void Render(LPDIRECT3DDEVICE9 pD3DDevice);
};


class CTerrain
{
public:
    CHeightMap					m_HeightMap;       
    int							m_cxTerrain;  
    int							m_czTerrain; 
	int							m_nBlockWidth;
	int							m_nBlockHeight;
	int							m_cxQuadsPerBlock;
	int							m_czQuadsPerBlock;
    CGridMesh					**m_ppMesh;            
    int							m_nMeshes;       
    D3DXVECTOR3					m_vScale;         
    D3DXMATRIX					m_mtxWorld;             

	ATTRIBUTEITEMSTRUCT			m_Attrubute[2];
	
	D3DMATERIAL9				m_Material;

	CTerrain(void);
	~CTerrain(void);

	LPDIRECT3DTEXTURE9			m_MapTex;
	LPDIRECT3DTEXTURE9			m_DetailTex;
	

	void Build(CScene *pScene, LPDIRECT3DDEVICE9 pD3DDevice, DWORD dwUsage=0, D3DPOOL dwMemoryPool=D3DPOOL_MANAGED);
	void Render(LPDIRECT3DDEVICE9 pD3DDevice, CScene *pScene);

    static void UpdatePlayerCallback(LPVOID pContext, CPlayer *pPlayer, float fTimeScale);
    static void UpdateCameraCallback(LPVOID pContext, CCamera *pCamera, float fTimeScale);
};
